package com.ld.security.common.mybatis.core.wrapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ld.security.common.core.base.SuperPo;
import com.ld.security.common.core.base.column.SuperColumn;
import com.ld.security.common.core.constant.CSuperConstant;
import com.ld.security.common.core.exception.ApiException;
import com.ld.security.common.core.util.ReflectionUtil;
import com.ld.security.common.core.util.SimpDateUtil;
import com.ld.security.common.core.util.StringUtil;
import com.ld.security.common.mybatis.anno.SqlKey;
import com.ld.security.common.mybatis.anno.SqlKeys;
import com.ld.security.common.mybatis.base.constant.SuperConstant;
import com.ld.security.common.mybatis.constant.SqlCondition;
import com.ld.security.common.mybatis.util.TypeUtil;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

public class EntityWrapper2<E> extends AbstWrapper<E> {

  public EntityWrapper2() {}

  private static List<SqlCondition> sqlConditionList =
      Arrays.asList(
          SqlCondition.eq, SqlCondition.like, SqlCondition.like_left, SqlCondition.like_right);

  /**
   * 根据列明构造条件
   *
   * @param columnName
   * @param condition
   * @param val
   * @return
   */
  private static <E> void addColumn(
      QueryWrapper<E> qw, String columnName, SqlCondition condition, Object val) {
    // 值预处理
    if (val == null) {
      return;
    } else if (val instanceof String) {
      if (StringUtil.isNull((String) val)) {
        return;
      }
    } else if (sqlConditionList.contains(condition)) {
      if (val instanceof SuperColumn) {
        SuperColumn sc = (SuperColumn) val;
        val = sc.getValue();
        if (((String) val).length() == 0) {
          return;
        }
      }
    } else if (val instanceof CSuperConstant.EnSuperEnum) {
      SuperConstant.SuperEnum se = (SuperConstant.SuperEnum) val;
      val = se.getValue();
    } else if (val instanceof Collection) {
      Collection col = (Collection) val;
      if (col.isEmpty()) {
        return;
      }
    }

    //日期处理
    if(val instanceof  List){
      List<?> list = (List) val;
      if(list.get(0) instanceof  Date){
        val =  list.stream().map(v -> {
          Date d = (Date) v;
          return SimpDateUtil.fomat(d);

        }).collect(Collectors.toList());
      }


    }else  if(val instanceof Date){
      val =  SimpDateUtil.fomat((Date)val);
    }

    //怀疑这个是日期
    if(condition== SqlCondition.between){
      if(val instanceof String){
        List vs = TypeUtil.getDateList(val.toString());
        if(vs != null){
          val = vs;
        }
      }
    }


    switch (condition) {
      case eq:
        {
          qw.eq(columnName, val);
          break;
        }
      case ne:
        {
          qw.ne(columnName, val);
          break;
        }
      case gt:
        {
          qw.gt(columnName, val);
          break;
        }
      case ge:
        {
          qw.ge(columnName, val);
          break;
        }
      case lt:
        {
          qw.lt(columnName, val);
          break;
        }
      case le:
        {
          qw.le(columnName, val);
          break;
        }
      case like:
        {
          qw.like(columnName, val.toString());
          break;
        }
      case like_left:
        {
          qw.likeLeft(columnName, val.toString());
          break;
        }
      case like_right:
        {
          qw.likeRight(columnName, val.toString());
          break;
        }
      case like_many:
        {
          Collection collection = (Collection) val;
          for (Object v : collection) {
            qw.or();
            qw.like(columnName, v);
          }
          break;
        }
      case in:
        {
          qw.in(columnName, (Collection<?>) val);

          break;
        }
      case between:
        {
          // 区间查询
          if (val instanceof String) {
            String str = val.toString();
            String[] keys = str.split("-");
            qw.between(columnName, keys[0], keys[1]);
          } else if (val instanceof List) {
            List keys = (List) val;
            qw.between(columnName, keys.get(0), keys.get(1));
          } else {
            ApiException.throw400("异常语法");
          }

          break;
        }
    }
  }

  /**
   * 根据属性名构造条件
   *
   * @param fieldName
   * @param condition
   * @param val
   * @return
   */
  public EntityWrapper2<E> addField(String fieldName, SqlCondition condition, Object val) {
    String columnName = StringUtil.javaToColumn(fieldName);
    addColumn(this, columnName, condition, val);
    return this;
  }

  private static <E> void addField(
      QueryWrapper<E> qw, Object query, String fieldName, SqlKey sqlKey) {
    Object val = ReflectionUtil.invokeGetter(query, fieldName);
    String columnName = "";
    if (val == null || val.equals("")) {
      return;
    }
    SqlCondition condition = SqlCondition.eq;
    if (sqlKey != null) {
      condition = sqlKey.value();
      columnName = sqlKey.name();
    }

    if (StringUtil.isNull(columnName)) {
      columnName = fieldName;
    }

    columnName = StringUtil.javaToColumn(columnName);

    if (sqlKey.and()) {

    } else {
      qw.or();
    }
    addColumn(qw, columnName, condition, val);
  }

  //    public static boolean isEmpty(Object po){
  //        if(po == null){
  //            return true;
  //        }
  //        for (Field field : ReflectionUtil.getAllDeclaredFields(po.getClass())) {
  //            SqlKey sqlKey = AnnotationUtils.findAnnotation(field,SqlKey.class);
  //            SqlKeys sqlKeys = AnnotationUtils.findAnnotation(field,SqlKeys.class);
  //            if(sqlKey != null || sqlKeys != null){
  //                Object val = ReflectionUtil.invokeGetter(po,field.getName());
  //                boolean b= ReflectionUtil.isNull(val);
  //                if(b){
  //                    return false;
  //                }
  //            }
  //        }
  //        return true;
  //    }

  public static <E> EntityWrapper2<E> newInstance() {
    return new EntityWrapper2<>();
  }

  static <E> void itemInit(QueryWrapper<E> qw, List<Item> ys, Object query) {

    for (Item y : ys) {
      if (y.value instanceof SuperPo) {

        SqlKey sqlKey = y.sqlKey;
        if (sqlKey.and()) {
          qw.and(
              (i) -> {
                initWhere(i, y.value);
                return i;
              });
        } else {
          qw.or(
              (i) -> {
                initWhere(i, y.value);
                return i;
              });
        }
      } else {
        // addColumn(qw,columnName,condition,val);

        addField(qw, query, y.fieldName, y.sqlKey);
      }
    }
  }

  private static <E> void initWhere(QueryWrapper<E> qw, Object query) {

    Class clazz = query.getClass();
    List<Field> fields = ReflectionUtil.getAllDeclaredFields(clazz);

    List<Item> items = new LinkedList<>();

    for (Field field : fields) {
      SqlKey sqlKey = field.getAnnotation(SqlKey.class);
      SqlKeys sqlKeys = field.getAnnotation(SqlKeys.class);
      if (sqlKey == null && sqlKeys == null) {
        continue;
      }
      Object val = ReflectionUtil.invokeGetter(query, field.getName());

      if (sqlKey != null) {
        items.add(new Item(sqlKey, field.getName(), val));
      } else if (sqlKeys != null) {
        for (SqlKey key : sqlKeys.value()) {
          items.add(new Item(key, field.getName(), val));
        }
      }
    }
    Map<Integer, List<Item>> map =
        items.stream().collect(Collectors.groupingBy(val -> val.sqlKey.index()));


    boolean b=false;

    for (Integer integer : map.keySet()) {
        List<Item>  ys = map.get(integer);
        if(b){
            qw.and(v -> {
                itemInit(v, ys, query);
                return v;
            });
        }else{
            b=true;
            itemInit(qw, ys, query);
        }

    }

  }

  public EntityWrapper2<E> initWhere(Object query) {
    // if(!isEmpty(query)){
    initWhere(this, query);
    // }
    return this;
  }

  public static <E> EntityWrapper2<E> of(SuperPo query) {
    EntityWrapper2 ew = new EntityWrapper2<>();
    ew.initWhere(query);
    return ew;
  }

  private static class Item {
    SqlKey sqlKey;
    String fieldName;
    Object value;

    public Item(SqlKey sqlKey, String fieldName, Object value) {
      this.sqlKey = sqlKey;
      this.fieldName = fieldName;

      this.value = value;
    }
  }
}
